package com.hyt.it.ogt.kq.service.bm.service.impl;

import java.time.LocalDate;
import java.time.LocalDateTime;
import java.time.format.DateTimeFormatter;
import java.util.ArrayList;
import java.util.Arrays;
import java.util.Collection;
import java.util.List;
import java.util.Optional;
import java.util.stream.Collectors;

import javax.annotation.Resource;

import org.apache.commons.collections4.CollectionUtils;
import org.apache.commons.lang3.StringUtils;
import org.redisson.api.RedissonClient;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
import org.springframework.beans.BeanUtils;
import org.springframework.stereotype.Service;
import org.springframework.transaction.annotation.Transactional;

import com.baomidou.mybatisplus.core.conditions.update.UpdateWrapper;
import com.baomidou.mybatisplus.core.metadata.IPage;
import com.hyt.common.apiInfor.ApiResponse;
import com.hyt.core.base.BaseEntity;
import com.hyt.core.base.BaseServiceImpl;
import com.hyt.core.constant.CommonConstant;
import com.hyt.core.enums.DelFlagEnum;
import com.hyt.core.util.FastJsonUtil;
import com.hyt.exception.exception.BusinessLogicException;
import com.hyt.it.ogt.cj.enums.ComponentNameEnum;
import com.hyt.it.ogt.cj.service.IProjectCollectInfoService;
import com.hyt.it.ogt.kq.common.bm.enums.BmAuditInfoSubmitAgainStatus;
import com.hyt.it.ogt.kq.common.bm.enums.BmAuditStatusEnum;
import com.hyt.it.ogt.kq.common.bm.enums.BmPayStatusEnum;
import com.hyt.it.ogt.kq.common.bm.enums.BmProjectNeedAuditEnum;
import com.hyt.it.ogt.kq.common.bm.enums.BmProjectNeedPayEnum;
import com.hyt.it.ogt.kq.common.bm.enums.BmProjectVerifyEnum;
import com.hyt.it.ogt.kq.common.bm.enums.ProjectOpenEnum;
import com.hyt.it.ogt.kq.common.bm.utils.Constant;
import com.hyt.it.ogt.kq.common.bm.utils.RedisUtil;
import com.hyt.it.ogt.kq.common.config.ConfigManager;
import com.hyt.it.ogt.kq.common.config.exception.InvalidRequestException;
import com.hyt.it.ogt.kq.common.utils.CompareUtil;
import com.hyt.it.ogt.kq.service.bm.mapper.NonOpenMapper;
import com.hyt.it.ogt.kq.service.bm.mapper.ProjectMapper;
import com.hyt.it.ogt.kq.service.bm.mapper.ProjectSubjectMapper;
import com.hyt.it.ogt.kq.service.bm.mapper.StudentPayMapper;
import com.hyt.it.ogt.kq.service.bm.mapper.StudentSubjectMapper;
import com.hyt.it.ogt.kq.service.bm.model.entity.NonOpenInfo;
import com.hyt.it.ogt.kq.service.bm.model.entity.Project;
import com.hyt.it.ogt.kq.service.bm.model.entity.ProjectSubject;
import com.hyt.it.ogt.kq.service.bm.model.entity.ProjectSubjectAreaLimit;
import com.hyt.it.ogt.kq.service.bm.model.entity.StudentInfo;
import com.hyt.it.ogt.kq.service.bm.model.entity.StudentProject;
import com.hyt.it.ogt.kq.service.bm.model.entity.StudentSubject;
import com.hyt.it.ogt.kq.service.bm.model.vo.KwStudentVo;
import com.hyt.it.ogt.kq.service.bm.model.vo.PayStatVo;
import com.hyt.it.ogt.kq.service.bm.model.vo.ProjectStatVo;
import com.hyt.it.ogt.kq.service.bm.model.vo.StudentInfoParam;
import com.hyt.it.ogt.kq.service.bm.model.vo.StudentListVo;
import com.hyt.it.ogt.kq.service.bm.model.vo.StudentStatVo;
import com.hyt.it.ogt.kq.service.bm.model.vo.StudentSubjectExportVo;
import com.hyt.it.ogt.kq.service.bm.model.vo.StudentSubjectVo;
import com.hyt.it.ogt.kq.service.bm.model.vo.SubjectVo;
import com.hyt.it.ogt.kq.service.bm.service.INonOpenService;
import com.hyt.it.ogt.kq.service.bm.service.IProjectExamService;
import com.hyt.it.ogt.kq.service.bm.service.IProjectSubjectAreaLimitService;
import com.hyt.it.ogt.kq.service.bm.service.IProjectSubjectService;
import com.hyt.it.ogt.kq.service.bm.service.IStudentInfoService;
import com.hyt.it.ogt.kq.service.bm.service.IStudentProjectService;
import com.hyt.it.ogt.kq.service.bm.service.IStudentSubjectService;
import com.hyt.it.ogt.kq.service.gov.service.ITaskOverviewService;

import cn.hutool.core.collection.CollUtil;
import cn.hutool.core.text.CharSequenceUtil;
import cn.hutool.core.text.StrPool;
import cn.hutool.core.util.ObjectUtil;
import cn.hutool.core.util.StrUtil;
import lombok.SneakyThrows;
import lombok.extern.slf4j.Slf4j;

/**
 * <p>
 * 考生报名科目表 服务实现类
 * </p>
 *
 * @author wangt
 * @since 2020-05-15
 */
@Service
@Slf4j
public class StudentSubjectServiceImpl extends BaseServiceImpl<StudentSubjectMapper, StudentSubject> implements IStudentSubjectService {

    private final Logger logger = LoggerFactory.getLogger(StudentVerifyServiceImpl.class);
    @Resource
    private RedissonClient redissonClient;
    @Resource
    private ProjectSubjectMapper projectSubjectMapper;
    @Resource
    private StudentSubjectMapper studentSubjectMapper;
    @Resource
    private ProjectMapper projectMapper;
    @Resource
    private StudentPayMapper studentPayMapper;
    @Resource
    private IStudentProjectService iStudentProjectService;
    @Resource
    private IProjectSubjectService iProjectSubjectService;
    @Resource
    private IProjectCollectInfoService iProjectCollectInfoService;
    @Resource
    private IProjectExamService iProjectExamService;
    @Resource
    private INonOpenService iNonOpenService;
    @Resource
    private NonOpenMapper nonOpenMapper;
    @Resource
    private IStudentSubjectService iStudentSubjectService;
    @Resource
    private RedisUtil redisUtil;
    @Resource
    private ITaskOverviewService iTaskOverviewService;
    @Resource
    IStudentInfoService iStudentInfoService;
    @Resource
    private ConfigManager configManager;
    @Resource
    private IProjectSubjectAreaLimitService iProjectSubjectAreaLimitService;


    @Override
    public List<ProjectSubject> getSubjectList(String projectId, String regId, String status) {
        List<ProjectSubject> studentSubjectList = projectSubjectMapper.getSubjectList(projectId, regId, status);
        return studentSubjectList;
    }

    @Override
    public String getStudentId(String regId, String projectId) {
        return projectSubjectMapper.getStudentId(regId, projectId);
    }

    @Override
    public boolean delete(String studentId, String projectId, String subjectId) {
        // 删除表数据
        return projectSubjectMapper.deleteBy(studentId, projectId, subjectId);
    }

    @Override
    public IPage<StudentListVo> getStudentList(StudentInfoParam param) {
        // 获取项目详情
        Project project = projectMapper.selectById(param.getProjectId());
        // 如果没有机构采集信息则不设置机构权限查询
        Boolean hasOfficePermission = iProjectCollectInfoService.isComponentRequired(param.getProjectId(), ComponentNameEnum.office.getCode());
        if (!hasOfficePermission) {
            param.setDeptIds(null);
        }
        // 获取考生列表
        LocalDateTime date = LocalDate.parse(configManager.getBmPageSearchDate(), DateTimeFormatter.ofPattern("yyyy-MM-dd")).atStartOfDay();
        IPage<StudentListVo> page ;
        if(project.getCreateDate().isBefore(date)){
            page = projectSubjectMapper.getStudentList(param);
        } else {
            page = projectSubjectMapper.getStudentListV2(param);
        }
        List<StudentListVo> list = page.getRecords();
        if (CollectionUtils.isEmpty(list)) {
            return page;
        }
        list.stream().filter(ObjectUtil::isNotEmpty).forEach(listInfo -> {
            // 查询考生报名的科目，缴费成功的数量
            if (listInfo.getInvoiceNum() == 0) {
                listInfo.setInvoiceStatus("未开具");
            }
            if (listInfo.getInvoiceNum() == listInfo.getTotal() && listInfo.getInvoiceNum() != 0) {
                listInfo.setInvoiceStatus("已开具");
            }
            if (listInfo.getInvoiceNum() > 0 && listInfo.getInvoiceNum() < listInfo.getTotal()) {
                listInfo.setInvoiceStatus("部分开具");
            }
            if (project.getIsPay() == 0) {
                // 项目设置不需要缴费
                listInfo.setPayStatus("无需缴费");
            } else {
                Integer countSucess = studentPayMapper.getStuSubjectNeedPay(listInfo.getStudentId());
                if (countSucess == 0 || listInfo.getPayNum() == 0) {
                    listInfo.setPayStatus("未缴费");
                } else if (countSucess == listInfo.getPayNum()) {
                    listInfo.setPayStatus("已缴费");
                } else if (countSucess > 0 && listInfo.getPayNum() > 0 && countSucess > listInfo.getPayNum()) {
                    listInfo.setPayStatus("部分缴费");
                }
                if(listInfo.getRefundNum() == listInfo.getNeedPayNum() && listInfo.getRefundNum() != 0){
                    listInfo.setPayStatus("全部已退费");
                }
            }
        });
        return page;
    }

    @Override
    public long getStudentListCount(String queryStr, String projectId, String auditState) {
        return projectSubjectMapper.getStudentListCount(queryStr, projectId, auditState);
    }

	@Override
	public void deleteStudentSubject(String studentId, String subjectId) {
		projectSubjectMapper.deleteStudentSubject(studentId, subjectId);
	}


    @Override
    public void deleteStudent(String projectId, String studentId) throws Exception {
        projectSubjectMapper.deleteStudent(studentId);
	}

    @Override
    public void updateStudentAudit(String studentId, String projectId) {
        projectSubjectMapper.updateStudentAudit(studentId, projectId);
    }

    @Override
    public void updateKwflag(String subjectId, String projectId, String kwFlag) {
        studentSubjectMapper.updateKwflag(subjectId, projectId, kwFlag);
    }

    @Override
    public List<StudentSubject> getStudentSbjects(String projectId, String studentId) {
        return studentSubjectMapper.getStudentSbjects(projectId, studentId);
    }

    @Override
    public StudentSubject getStudentSbject(String subjectId, String studentId, String projectId) {
        return studentSubjectMapper.getStudentSbject(studentId, subjectId, projectId);
    }

    @Override
    public List<StudentSubject> queryStudentSubject(String isAudit, String isPay, String subjectId, String studentId, List<String> permissionList, String projectId) {
        return studentSubjectMapper.queryStudentSubject(isAudit, isPay, subjectId, studentId, permissionList, projectId);
    }

    @Override
    @Transactional(rollbackFor = Exception.class)
    public void updateStudentFlag(List<KwStudentVo> list) throws Exception {
        for (int i = 0; i < list.size(); i++) {
            studentSubjectMapper.updateStudentFlag(list.get(i).getStudentId(), list.get(i).getEnrollId(),
                    list.get(i).getSubjectId());
        }
    }

    @Override
    public List<StudentStatVo> statByExamId(String examId) {
        return studentSubjectMapper.statByExamId(examId);
    }

    @Override
    public List<PayStatVo> statPayByProjectId(String projectId, List<String> permissionList, String deptId) {
        return studentSubjectMapper.statPayByProjectId(projectId, permissionList, deptId);
    }

    @Override
    @Transactional(rollbackFor = Exception.class)
    public ApiResponse<String> deleteStudentSubject(StudentSubjectVo studentSubjectVo) {
        String[] strs = studentSubjectVo.getStudentId().split(",");
        List<String> deleteStudentList = new ArrayList<>();
        for (String studentId : strs) {
            deleteStudentList.add(studentId);
            this.delete(studentId, studentSubjectVo.getProjectId(), studentSubjectVo.getSubjectId());
        }
        return ApiResponse.<String>builder().code(Constant.RESPONSE_CODE_SUCCESS).data("删除成功！").build();

    }


    @Override
    @Transactional(rollbackFor = Exception.class)
    public ApiResponse<String> addStudentSubject(SubjectVo subjectVo)  {
        LocalDateTime nowTime = LocalDateTime.now();
        
        String regId = subjectVo.getRegId();
        String projectId = subjectVo.getProjectId();
        String subjectIdList = subjectVo.getSubjectIdList();

        if (StrUtil.isBlank(regId)) {
            BusinessLogicException.throwException(31081109, "考生账号不能为空");
        }
        if (StrUtil.isBlank(projectId)) {
            BusinessLogicException.throwException(31101201, "缺少报名目标");
        }
        // 查询student id
        String studentId = this.getStudentId(regId, projectId);
        // 如果全部科目都报完名直接下一步
        if (StringUtils.isEmpty(subjectIdList)) {
            return ApiResponse.<String>builder().code(Constant.RESPONSE_CODE_SUCCESS).data(studentId).build();
        }

        // 项目信息
        Project project = projectMapper.selectById(projectId);
        if (project == null) {
            BusinessLogicException.throwException(31101202, "无效的报名目标");
        }

        // 校验科目报考的时间节点
        ApiResponse<String> verityBmEndTime = verityBmEndTime(project);
        if (null != verityBmEndTime) {
            return verityBmEndTime;
        }

        // 校验考生报名的科目是否超过阈值
        ApiResponse<String> verifyBmSubjectCountExceedingThreshold = verifyBmSubjectCountExceedingThreshold(subjectIdList, project, regId, studentId);
        if (null != verifyBmSubjectCountExceedingThreshold) {
            return verifyBmSubjectCountExceedingThreshold;
        }

        List<String> subjectIds = StrUtil.split(subjectIdList, StrPool.COMMA)
                .stream()
                .filter(StrUtil::isNotBlank)
                .distinct()
                .collect(Collectors.toList());
        for (int i = 0; i < subjectIds.size(); i++) {
            String subjectId = subjectIds.get(i);
            ProjectSubject projectSubject = iProjectSubjectService.queryBySubjectId(projectId, subjectId);
            String subjecName = projectSubject.getSubjectName();
            StudentSubject studentSubject = new StudentSubject();
            // 获取当前科目是否是已经存在报考
            StudentSubject subject = studentSubjectMapper.getStudentSbject(studentId, subjectId, projectId);
            // 如果是已经缴费或者是已经审核则不处理
            if (null != subject && null != subject.getPay() && BmPayStatusEnum.PAY.getPayStatus().equals(subject.getPay())) {
                continue;
            }
            // 如果项目需要审核，则报名科目提交的时候，将科目设为待审核
            if (null != project.getIsVerify() && BmProjectNeedAuditEnum.NEEDAUDIT.getAuditStatus().equals(project.getIsVerify())) {
                studentSubject.setIsAudit(BmAuditStatusEnum.PENDINGAPPROVAL.getAuditStatus());
            }
            if (subject != null) {
                studentSubject.setUpdateDate(nowTime);
                studentSubject.setId(subject.getId());
                studentSubject.setSubjectName(subjecName);
                studentSubject.setSubjectId(subjectId);
                studentSubject.setProjectId(projectId);
                studentSubject.setStudentId(studentId);
                // 如果科目已经缴费则审核通过
                if (null != studentSubject.getPay() && BmPayStatusEnum.PAY.getPayStatus().equals(studentSubject.getPay())) {
                    studentSubject.setIsAudit(BmAuditStatusEnum.APPROVED.getAuditStatus());
                }
                UpdateWrapper<StudentSubject> updateWrapper = new UpdateWrapper<>();
                updateWrapper.lambda().eq(StudentSubject::getId, subject.getId());
                this.update(studentSubject, updateWrapper);
            } else {
                studentSubject.setIsPay(projectSubject.getIsPay());
                studentSubject.setSubjectName(subjecName);
                studentSubject.setSubjectId(subjectId);
                studentSubject.setProjectId(projectId);
                studentSubject.setStudentId(studentId);
                studentSubject.setCreateDate(nowTime);
                this.save(studentSubject);
            }
        }
        this.updateStudentAudit(studentId, projectId);

        // 判断是否非开放性报名
        if (ProjectOpenEnum.UNOPEN.getOpenStatus().equals(project.getIsOpen())) {
            // 更新报名资格信息
            String cardNumString = nonOpenMapper.queryStuCardNum(studentId, projectId);
            NonOpenInfo nonOpenInfo = iNonOpenService.queryStudentByCardNum(projectId, cardNumString);
            StudentProject studentProject = new StudentProject();
            studentProject.setId(studentId);
            studentProject.setAncestors(nonOpenInfo.getAncestors());
            studentProject.setDeptId(nonOpenInfo.getDeptId());
            UpdateWrapper<StudentProject> updateWrapper = new UpdateWrapper<>();
            updateWrapper.lambda().eq(StudentProject::getId, studentId);
            iStudentProjectService.update(studentProject, updateWrapper);
            iNonOpenService.updateBm(studentId, projectId);
        }
        return ApiResponse.<String>builder().code(Constant.RESPONSE_CODE_SUCCESS).data(studentId).build();
    }
    /****
     * 校验科目报考的时间节点
     * @param project
     * @return
     */
    private ApiResponse<String> verityBmEndTime(Project project) {
        LocalDateTime nowTime = LocalDateTime.now();
        // 科目列表
        if (null != project.getAuditEndTime() && nowTime.isAfter(project.getAuditEndTime())) {
            return ApiResponse.<String>builder().code(Constant.RESPONSE_CODE_15023).data("报名时间已截止").build();
        }
        if (null == project.getAuditEndTime() && nowTime.isAfter(project.getEndTime())) {
            return ApiResponse.<String>builder().code(Constant.RESPONSE_CODE_15023).data("报名时间已截止").build();
        }
        if (nowTime.isBefore(project.getBeginTime())) {
            return ApiResponse.<String>builder().code(Constant.RESPONSE_CODE_15024).data("还未到报名时间").build();
        }
        return null;
    }


    /*****
     *
     * 校验考生报名的科目是否超过阈值
     * @param addSubjectIds 前端报名的科目
     * @param project  报名项目
     * @return
     */
    private ApiResponse<String> verifyBmSubjectCountExceedingThreshold(String addSubjectIds, Project project, String userId, String studentId) {
        String projectId = project.getId();
        List<ProjectSubject> studentProjectSubjects = projectSubjectMapper.getSubjectList(projectId, userId, null);
        // 计算考生报考的科目和项目设置的最大报考科目是不是超过阈值
        int bmNum = 0;
        // 已报考的科目id
        List<String> hasBm = new ArrayList<>();
        for (ProjectSubject projectSubject : studentProjectSubjects) {
            // 如果科目已经报考
            if ("1".equals(projectSubject.getStatus())) {
                // 已报名科目
                bmNum++;
                hasBm.add(projectSubject.getSubjectId());
            }
        }

        List<String> newBmList = new ArrayList<>();
        if (StringUtils.isNotBlank(addSubjectIds)) {
            newBmList = Arrays.asList(addSubjectIds.split(","));
            if (CollUtil.isNotEmpty(newBmList)) {
                bmNum += newBmList.stream().filter(str -> !hasBm.contains(str)).count();
            }
        }

        // 判断科目是否报最少、最多
        Integer maxInteger = project.getMaxSubject();
        Integer minInteger = project.getMinSubject();
        if (minInteger > bmNum) {
            return ApiResponse.<String>builder().code(Constant.RESPONSE_CODE_15021).data("报名科目失败，请至少选择" + minInteger + "门科目！").build();
        }
        if (bmNum > maxInteger) {
            return ApiResponse.<String>builder().code(Constant.RESPONSE_CODE_15022).data("报名科目失败，最多只能选择" + maxInteger + "门科目！").build();
        }

        if(CollUtil.isNotEmpty(newBmList)) {
            for (String subjectId : newBmList) {
                Boolean validateResult = validateStudentSubjectRegistNum(subjectId);
                if(!validateResult) {
                    return ApiResponse.<String>builder().code(31101503).data("科目剩余报名数不足").build();
                }
                // 获取报名区域 studentId
                String bmAreaCollId = projectMapper.getCollectIdByProject(ProjectSubjectAreaLimit.getBmAreaCollKey(), projectId, DelFlagEnum.NORMAL.getCode());
                // 获取报名考生数据
                if (CharSequenceUtil.isNotEmpty(bmAreaCollId)) {
                    String bmArea = iStudentInfoService.getValueByStudentIdAndCollectInfoId(projectId, studentId, bmAreaCollId);
                    // 如果考生选择了报考区域
                    if(StrUtil.isNotEmpty(bmArea)) {
                        Boolean checkExcess = iProjectSubjectAreaLimitService.checkExcessBySubjectIdAndArea(projectId, studentId, subjectId, bmAreaCollId,  bmArea);
                        if (checkExcess) {
                            return ApiResponse.<String>builder().code(31101203).data("您所报名的考试科目名额已满，请您选择其他科目或等待下次考试报名。感谢您的理解与支持").build();
                        }
                    } else { // 如果考生没有选择报考区域
                        Boolean checkSubjectConfigLimit = iProjectSubjectAreaLimitService.checkSubjectConfigLimit(projectId, subjectId);
                        if (checkSubjectConfigLimit) {
                            return ApiResponse.<String>builder().code(31101204).data("预约科目配置了区域限额，请先填写基本信息选择报考区域").build();
                        }
                    }
                }
            }
        }
        return null;
    }


    /**
     * 获取用户报名的科目
     *
     * @param
     * @return
     */
    @Override
    public List<StudentSubject> queryRegSubject(String regId, String projectId) {
        return studentSubjectMapper.queryRegSubject(regId, projectId);
    }

    /**
     * @Params:
     * @Description: 报名首页，项目报名人数统计
     * @Author: STARF
     * @CreateDate: 2022/5/5 11:48
     **/
    @Override
    public ProjectStatVo getProjectApplyNum(String projectId, String deptId) {
        return studentSubjectMapper.queryProjectApplyNum(projectId, deptId);
    }

    @Override
    public Optional<Integer> countAreaPersonTimeNum(String projectId, String areaCollectInfoId, String areaCode, String deptId) {
        return studentSubjectMapper.countAreaPersonTimeNum(projectId, areaCollectInfoId, areaCode, deptId);
    }

    @Override
    public Optional<Integer> countPersonTimeNum(String projectId, String deptId) {
        return studentSubjectMapper.countPersonTimeNum(projectId, deptId);
    }

    @Override
    public Boolean validateStudentSubjectRegistNum(String projectId, String subjectId) {
        // 获取报名科目信息
        ProjectSubject projectSubject = iProjectSubjectService.queryBySubjectId(projectId, subjectId);
        // 获取科目的最大报名人数
        Integer maxNumberofRegister = projectSubject.getMaxNumberofRegister();
        // 如果不限制，则直接返回true
        if (CommonConstant.ZERO == projectSubject.getLimitSubjectRegister()) {
            return Boolean.TRUE;
        }
        // 获取库中已报名数
        Integer dbcount = this.countBySubjectId(projectId, subjectId);
        if (dbcount < maxNumberofRegister) {
            return Boolean.TRUE;
        }
        return Boolean.FALSE;
    }


	@Override
	public List<StudentSubject> listByStudentIds(List<String> studentIds) {
		return this.lambdaQuery()
				.in(StudentSubject::getStudentId, studentIds)
				.eq(BaseEntity::getDelFlag, Boolean.FALSE)
				.list();
	}

    @Override
    public List<StudentSubject> listByStudentId(String studentId) {
        return this.lambdaQuery()
                .eq(StudentSubject::getStudentId, studentId)
                .eq(BaseEntity::getDelFlag, Boolean.FALSE)
                .list();
    }

    @Override
    public String getCommaByStudentId(String studentId) {
        return this.listByStudentId(studentId)
                .stream()
                .map(StudentSubject::getSubjectName)
                .filter(StrUtil::isNotBlank)
                .collect(Collectors.joining(StrPool.COMMA));
    }

    /****
     * 提交考生的科目信息
     * @param subjectVo
     * @return
     * @throws Exception
     */
    @Transactional(rollbackFor = Exception.class)
    @SneakyThrows
    public ApiResponse<String> commitStudentSubjectApi(SubjectVo subjectVo, List<StudentSubject> subjectList) {
        logger.info("## commitStudentSubject json{}", FastJsonUtil.getBeanToJson(subjectVo));
        if (StrUtil.isEmptyIfStr(subjectVo.getSubjectIdList())) {
            BusinessLogicException.throwException(31101504, "报名提交科目不能为空", subjectVo);
        }

        List<String> newsSubkjectIdList = StrUtil.split(subjectVo.getSubjectIdList(), StrPool.COMMA);
        // 查询student id
        String studentId = this.getStudentId(subjectVo.getRegId(), subjectVo.getProjectId());
        // 如果为空说明是重复提交数据
        if (CollUtil.isEmpty(newsSubkjectIdList)) {
            return ApiResponse.<String>builder().code(Constant.RESPONSE_CODE_SUCCESS).data(studentId).build();
        }

        // 如果是非开放性报名
        List<StudentInfo> studentInfos = iStudentInfoService.listByStudentId(subjectVo.getProjectId(), studentId);
        if (CollUtil.isEmpty(studentInfos)) {
            BusinessLogicException.throwException(31101506, "未查询到考生的报名基础信息", subjectVo);
        }
        // 校验报名考生是否有资格
        iNonOpenService.checkStudentHasQualifications(subjectVo.getProjectId(), studentInfos, newsSubkjectIdList);

        List<String> dbSubjectIdList = new ArrayList<>();
        // 如果为空说明是重复提交数据
        if (CollUtil.isNotEmpty(subjectList)) {
            dbSubjectIdList = subjectList.stream().map(StudentSubject::getSubjectId).collect(Collectors.toList());
        }
        //如果考生没有报过科目，直接添加
        if (CollUtil.isEmpty(dbSubjectIdList)) {
            return addStudentSubject(subjectVo);
        }

        List<String> addList = new ArrayList<>();
        List<String> delList = new ArrayList<>();
        CompareUtil.filterList(dbSubjectIdList, newsSubkjectIdList, addList, delList);

        //重新提交时，将审核未通过的报名设置为待审核
        List<StudentSubject> dbExitSubjectList = iStudentSubjectService.queryRegSubject(subjectVo.getRegId(), subjectVo.getProjectId());
        for (StudentSubject studentSubject : dbExitSubjectList) {
            if (null != studentSubject.getIsAudit() && BmAuditStatusEnum.UNAPPROVED.getAuditStatus().equals(studentSubject.getIsAudit())) {
                iStudentSubjectService.lambdaUpdate()
                        .set(StudentSubject::getIsAudit, BmAuditStatusEnum.PENDINGAPPROVAL.getAuditStatus())
                        .eq(BaseEntity::getId, studentSubject.getId())
                        .update();
                StudentProject studentProject = iStudentProjectService.getProjectStudent(subjectVo.getProjectId(), subjectVo.getRegId());
                studentProject.setIsAudit(BmAuditStatusEnum.PENDINGAPPROVAL.getAuditStatus());
                // 设置资料补交状态为已补交
                studentProject.setBmInformationSubmitAgain(BmAuditInfoSubmitAgainStatus.SUPPLEMENTARY.getStatus());
                studentProject.setUpdateDate(LocalDateTime.now());
                iStudentProjectService.updateById(studentProject);
            }
        }
        /******************如果考生已有报名的科目，则需判断是新增科目还是取消科目*************/
        Project project = projectMapper.selectById(subjectVo.getProjectId());

        // 如果项目需要审核
        if (BmProjectVerifyEnum.VERIFY.getVerifyStatus().equals(project.getIsVerify())) {
            // 遍历所有的考生科目信息
            for (StudentSubject studentSubject : dbExitSubjectList) {
                // 如果是已经缴费或者是已经审核则不处理
                if (null != studentSubject.getPay() && BmPayStatusEnum.PAY.getPayStatus().equals(studentSubject.getPay())) {
                    continue;
                }
                if (null != studentSubject.getIsAudit() && BmProjectVerifyEnum.VERIFY.getVerifyStatus().equals(studentSubject.getIsAudit())) {
                    continue;
                }
                ProjectSubject projectSubject = projectSubjectMapper.queryBySubjectId(studentSubject.getProjectId(), studentSubject.getSubjectId());
                if (null != projectSubject && null != projectSubject.getIsPay() && BmProjectNeedPayEnum.PAY.getPayStatus().equals(projectSubject.getIsPay())) {
                    if (null != studentSubject.getIsAudit() && BmAuditStatusEnum.APPROVED.getAuditStatus().equals(studentSubject.getIsAudit())) {
                        continue;
                    }
                }
                if (delList.contains(studentSubject.getSubjectId())) {
                    iStudentSubjectService.delete(studentSubject.getStudentId(), studentSubject.getProjectId(), studentSubject.getSubjectId());
                }
            }
        } else {
            for (StudentSubject studentSubject : dbExitSubjectList) {
                // 如果科目已经缴费
                if (null != studentSubject.getPay() && BmPayStatusEnum.PAY.getPayStatus().equals(studentSubject.getPay())) {
                    continue;
                }
                if (delList.contains(studentSubject.getSubjectId())) {
                    iStudentSubjectService.delete(studentSubject.getStudentId(), studentSubject.getProjectId(), studentSubject.getSubjectId());
                }
            }
        }

        // 如果没有新增科目
        if (CollUtil.isEmpty(addList)) {
            return ApiResponse.<String>builder().code(Constant.RESPONSE_CODE_SUCCESS).data(studentId).build();
        }

        StringBuilder addSubjectIds = new StringBuilder();
        for (String addSubjectId : addList) {
            addSubjectIds.append(addSubjectId).append(StrPool.COMMA);
        }
        // 走新增科目逻辑
        SubjectVo newSubjectVo = new SubjectVo();
        BeanUtils.copyProperties(subjectVo, newSubjectVo);
        newSubjectVo.setSubjectIdList(addSubjectIds.deleteCharAt(addSubjectIds.length() - 1).toString());
        ApiResponse<String> response = addStudentSubject(subjectVo);
        if (response.getCode().equals(Constant.RESPONSE_CODE_SUCCESS)) {
            return response;
        } else {
            throw new InvalidRequestException(response.getCode());
        }
    }



	@Override
	public Integer countBySubjectId(String subjectId) {
		return lambdaQuery()
				.eq(StudentSubject::getSubjectId, subjectId)
				.eq(BaseEntity::getDelFlag, Boolean.FALSE)
				.count();
	}
    @Override
    public Integer countBySubjectId(String projectId, String subjectId) {
        return lambdaQuery()
                .eq(StudentSubject::getProjectId, projectId)
                .eq(StudentSubject::getSubjectId, subjectId)
                .eq(BaseEntity::getDelFlag, Boolean.FALSE)
                .count();
    }

    @Override
    public List<StudentSubjectExportVo> getStudentSubjectNamesByProjectId(String projectId) {
        return studentSubjectMapper.getStudentSubjectNamesList(projectId);
    }
    
    @SneakyThrows
    @Override
    public Boolean validateStudentSubjectRegistNum(String subjectId) {
        // 获取报名科目信息
        ProjectSubject projectSubject = iProjectSubjectService.queryBySubjectId(subjectId);
        // 获取科目的最大报名人数
        Integer maxNumberofRegister = projectSubject.getMaxNumberofRegister();
        // 如果不限制，则直接返回true
        if (CommonConstant.ZERO == projectSubject.getLimitSubjectRegister()) {
            return Boolean.TRUE;
        }
        // 获取库中已报名数
        Integer dbcount = this.countBySubjectId(subjectId);
        if (dbcount < maxNumberofRegister) {
            return Boolean.TRUE;
        }
        return Boolean.FALSE;
    }

    /**
     * //TODO 添加override说明
     * @see com.hyt.it.ogt.kq.service.bm.service.IStudentSubjectService#commitStudentSubjectApi(com.hyt.it.ogt.kq.service.bm.model.vo.SubjectVo)
     **/
    @Override
    public ApiResponse<String> commitStudentSubjectApi(SubjectVo subjectVo) {
        // TODO Auto-generated method stub
        return null;
    }

    

    @Override
    public List<String> getQualificationSubject(String projectId, String userId) {
        if (StrUtil.isBlank(userId)) {
            BusinessLogicException.throwException(31102102, "无效的考生信息");
        }
        if (StrUtil.isBlank(projectId)) {
            BusinessLogicException.throwException(31102103, "无效的报名信息");
        }

        StudentProject projectStudent = iStudentProjectService.getProjectStudent(projectId, userId);
        if (projectStudent == null) {
            BusinessLogicException.throwException(31102104, "考生还未填报当前报名");
        }

        List<StudentInfo> studentInfos = iStudentInfoService.listByStudentId(projectId, projectStudent.getId());
        if (CollUtil.isEmpty(studentInfos)) {
            BusinessLogicException.throwException(31102105, "考生还未填报报名采集信息");
        }

        // 获取证件号的采集字段
        String idCardCollectId = projectMapper.getCollectIdByProject(ComponentNameEnum.idcard.getCode(), projectId, DelFlagEnum.NORMAL.getCode());
        // 获取考生的证件号码
        List<String> idCards = studentInfos.stream()
                // 获取证件号的报名采集对应的考生信息
                .filter(data -> StrUtil.equals(data.getProjectCollectInfoId(), idCardCollectId))
                .map(StudentInfo::getValue)
                .filter(StrUtil::isNotBlank)
                .distinct()
                .collect(Collectors.toList());
        List<NonOpenInfo> openInfoList = idCards.stream()
                // 获取报名资格的对应证件号信息
                .map(idCard -> nonOpenMapper.queryStudentByCardNum(projectId, idCard))
                .filter(ObjectUtil::isNotEmpty)
                .collect(Collectors.toList());
        // 获取证件号码对应的科目ID集合
        List<String> nonOpenSubjectIds = openInfoList.stream()
                // 获取科目ID集合
                .map(NonOpenInfo::getSubjectIds)
                .map(data -> StrUtil.split(data, StrPool.COMMA))
                .filter(CollUtil::isNotEmpty)
                .flatMap(Collection::stream)
                .filter(StrUtil::isNotBlank)
                .distinct()
                .collect(Collectors.toList());
        return nonOpenSubjectIds;
    }
}
